home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / make < prev    next >
Encoding:
Internet Message Format  |  1986-12-02  |  38.5 KB

  1. Subject:  v07i071:  Public-domain MAKE
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: caret@fairlight.oz
  6. Mod.sources: Volume 7, Issue 71
  7. Archive-name: make
  8.  
  9. [  This seems to be fairly complete for the V7 make.  People with
  10.    source licenses will appreciate the appearance of this code.  --r$  ]
  11.  
  12. #!/bin/sh
  13. # This is a shell archive.  Remove anything before this line,
  14. # then unpack it by saving it in a file and typing "sh file".
  15. # If all goes well, you will see the message "No problems found."
  16.  
  17. # Exit status; set to 1 on "wc" errors or if would overwrite.
  18. STATUS=0
  19. # Contents:  README Makefile h.h check.c input.c macro.c main.c
  20. #    make.c reader.c rules.c
  21.  
  22. echo x - README
  23. if test -f README ; then
  24.     echo README exists, putting output in $$README
  25.     OUT=$$README
  26.     STATUS=1
  27. else
  28.     OUT=README
  29. fi
  30. sed 's/^X//' > $OUT <<'@//E*O*F README//'
  31. XFollowing is a repost of the public domain 'make' that I posted
  32. Xto net.sources a couple of months ago.  I have fixed a few bugs, and
  33. Xadded some more features, and the resulting changes amounted to
  34. Xabout as much text as the whole program (hence the repost).
  35.  
  36. XFor those that missed the net.sources posting, this is a public domain
  37. Xre-implementation of the UNIX make program.  There is no manual included;
  38. Xfor documentation, refer to a UNIX manual, or the source.
  39.  
  40. XHere is a list of the changes made:
  41.  
  42. Xi)    If '-' (ignore) or '@' (silent) where used at the start
  43. X    of a command, their effect was not turned off for the following
  44. X    commands.
  45. Xii)    A special target (.SUFFIXES, .PRECIOUS) or a rule (.c.o, .a.o),
  46. X    if first in the file would be taken as the default target.
  47. X    This resulted in error messages like "Don't know how to
  48. X    make .c", because things like .SUFFIXES were being made.
  49. X    This was further complicated by ---
  50. Xiii)    Special target lines with no dependents (ie. .SUFFIXES:\n)
  51. X    were not clearing out the existing dependents like
  52. X    they should.
  53. Xiv)    Default rules could not be redefined because of the error
  54. X    checking for commands being defined twice.  Now you are
  55. X    allowed to define a target beinging with '.', having
  56. X    no dependents with commands.
  57. Xv)    The -q option didn't do the time comparison correctly,
  58. X    or clear the variable used to keep track of this.  Thus
  59. X    it didn't work very well.
  60. Xvi)    The syntax ${..} for macro's supported by UNIX make was
  61. X    not supported.
  62. Xvii)    There wuz a couple of spelling errors.
  63. Xviii)    When make checked for implicit rules on targets without
  64. X    a suffix, there were problems.  (Note: The ~ feature of
  65. X    UNIX make wasn't and still isn't supported)
  66. Xix)    The -n option did not print @ lines like it was supposed to.
  67. Xx)    :: added.  (See UNIX manual)
  68. Xxi)    $? added.  (see UNIX manual)
  69. @//E*O*F README//
  70. chmod u=rw,g=rw,o=rw $OUT
  71.  
  72. echo x - Makefile
  73. if test -f Makefile ; then
  74.     echo Makefile exists, putting output in $$Makefile
  75.     OUT=$$Makefile
  76.     STATUS=1
  77. else
  78.     OUT=Makefile
  79. fi
  80. sed 's/^X//' > $OUT <<'@//E*O*F Makefile//'
  81. X# Makefile for make!
  82.  
  83.  
  84.  
  85. XOBJS    =    check.o input.o macro.o main.o \
  86. X        make.o reader.o rules.o
  87.  
  88. Xm:        $(OBJS)
  89. X    cc -o m $(OBJS)
  90.  
  91. X$(OBJS):    h.h
  92. @//E*O*F Makefile//
  93. chmod u=rw,g=rw,o=rw $OUT
  94.  
  95. echo x - h.h
  96. if test -f h.h ; then
  97.     echo h.h exists, putting output in $$h.h
  98.     OUT=$$h.h
  99.     STATUS=1
  100. else
  101.     OUT=h.h
  102. fi
  103. sed 's/^X//' > $OUT <<'@//E*O*F h.h//'
  104. X/*
  105. X *    Include header for make
  106. X */
  107.  
  108.  
  109. X#ifndef uchar
  110. X#ifdef os9
  111. X#define uchar        char
  112. X#define void        int
  113. X#define fputc        putc
  114. X#else
  115. X#define uchar        unsigned char
  116. X#endif
  117. X#endif
  118.  
  119. X#define bool        uchar
  120. X#define time_t        long
  121. X#define TRUE        (1)
  122. X#define FALSE        (0)
  123. X#define max(a,b)    ((a)>(b)?(a):(b))
  124.  
  125. X#define DEFN1        "makefile"        /*  Default names  */
  126. X#ifdef unix
  127. X#define DEFN2        "Makefile"
  128. X#endif
  129. X#ifdef eon
  130. X#define DEFN2        "Makefile"
  131. X#endif
  132. X/* os9 is case insensitive */
  133.  
  134. X#define LZ        (1024)            /*  Line size  */
  135.  
  136.  
  137.  
  138. X/*
  139. X *    A name.  This represents a file, either to be made, or existant
  140. X */
  141.  
  142. Xstruct name
  143. X{
  144. X    struct name *        n_next;        /* Next in the list of names */
  145. X    char *            n_name;        /* Called */
  146. X    struct line *        n_line;        /* Dependencies */
  147. X    time_t            n_time;        /* Modify time of this name */
  148. X    uchar            n_flag;        /* Info about the name */
  149. X};
  150.  
  151. X#define N_MARK        0x01            /* For cycle check */
  152. X#define N_DONE        0x02            /* Name looked at */
  153. X#define N_TARG        0x04            /* Name is a target */
  154. X#define N_PREC        0x08            /* Target is precious */
  155. X#define N_DOUBLE    0x10            /* Double colon target */
  156.  
  157. X/*
  158. X *    Definition of a target line.
  159. X */
  160. Xstruct    line
  161. X{
  162. X    struct line *        l_next;        /* Next line (for ::) */
  163. X    struct depend *        l_dep;        /* Dependents for this line */
  164. X    struct cmd *        l_cmd;        /* Commands for this line */
  165. X};
  166.  
  167.  
  168. X/*
  169. X *    List of dependents for a line
  170. X */
  171. Xstruct    depend
  172. X{
  173. X    struct depend *        d_next;        /* Next dependent */
  174. X    struct name *        d_name;        /* Name of dependent */
  175. X};
  176.  
  177.  
  178. X/*
  179. X *    Commands for a line
  180. X */
  181. Xstruct    cmd
  182. X{
  183. X    struct cmd *        c_next;        /* Next command line */
  184. X    char *            c_cmd;        /* Command line */
  185. X};
  186.  
  187.  
  188. X/*
  189. X *    Macro storage
  190. X */
  191. Xstruct    macro
  192. X{
  193. X    struct macro *        m_next;        /* Next variable */
  194. X    char *            m_name;        /* Called ... */
  195. X    char *            m_val;        /* Its value */
  196. X    uchar            m_flag;        /* Infinite loop check */
  197. X};
  198.  
  199. Xextern char *        myname;
  200. Xextern struct name    namehead;
  201. Xextern struct macro *    macrohead;
  202. Xextern struct name *    firstname;
  203. Xextern bool        silent;
  204. Xextern bool        ignore;
  205. Xextern bool        rules;
  206. Xextern bool        dotouch;
  207. Xextern bool        quest;
  208. Xextern bool        domake;
  209. Xextern char        str1[];
  210. Xextern char        str2[];
  211. Xextern int        lineno;
  212.  
  213. Xchar *            fgets();
  214. Xchar *            index();
  215. Xchar *            rindex();
  216. Xchar *            malloc();
  217. Xextern int        errno;
  218.  
  219. Xchar *            getmacro();
  220. Xstruct macro *        setmacro();
  221. Xvoid            input();
  222. Xvoid            error();
  223. Xvoid            fatal();
  224. Xint            make();
  225. Xstruct name *        newname();
  226. Xstruct depend *        newdep();
  227. Xstruct cmd *        newcmd();
  228. Xvoid            newline();
  229. Xchar *            suffix();
  230. Xvoid            touch();
  231. Xvoid            makerules();
  232. Xchar *            gettok();
  233. Xvoid            precious();
  234. @//E*O*F h.h//
  235. chmod u=rw,g=rw,o=rw $OUT
  236.  
  237. echo x - check.c
  238. if test -f check.c ; then
  239.     echo check.c exists, putting output in $$check.c
  240.     OUT=$$check.c
  241.     STATUS=1
  242. else
  243.     OUT=check.c
  244. fi
  245. sed 's/^X//' > $OUT <<'@//E*O*F check.c//'
  246. X/*
  247. X *    Check structures for make.
  248. X */
  249.  
  250. X#include <stdio.h>
  251. X#include "h.h"
  252.  
  253.  
  254. X/*
  255. X *    Prints out the structures as defined in memory.  Good for check
  256. X *    that you make file does what you want (and for debugging make).
  257. X */
  258. Xvoid
  259. Xprt()
  260. X{
  261. X    register struct name *        np;
  262. X    register struct depend *    dp;
  263. X    register struct line *        lp;
  264. X    register struct cmd *        cp;
  265. X    register struct macro *        mp;
  266.  
  267.  
  268. X    for (mp = macrohead; mp; mp = mp->m_next)
  269. X        fprintf(stderr, "%s = %s\n", mp->m_name, mp->m_val);
  270.  
  271. X    fputc('\n', stderr);
  272.  
  273. X    for (np = namehead.n_next; np; np = np->n_next)
  274. X    {
  275. X        if (np->n_flag & N_DOUBLE)
  276. X            fprintf(stderr, "%s::\n", np->n_name);
  277. X        else
  278. X            fprintf(stderr, "%s:\n", np->n_name);
  279. X        if (np == firstname)
  280. X            fprintf(stderr, "(MAIN NAME)\n");
  281. X        for (lp = np->n_line; lp; lp = lp->l_next)
  282. X        {
  283. X            fputc(':', stderr);
  284. X            for (dp = lp->l_dep; dp; dp = dp->d_next)
  285. X                fprintf(stderr, " %s", dp->d_name->n_name);
  286. X            fputc('\n', stderr);
  287.  
  288. X            for (cp = lp->l_cmd; cp; cp = cp->c_next)
  289. X#ifdef os9
  290. X                fprintf(stderr, "-   %s\n", cp->c_cmd);
  291. X#else
  292. X                fprintf(stderr, "-\t%s\n", cp->c_cmd);
  293. X#endif
  294. X            fputc('\n', stderr);
  295. X        }
  296. X        fputc('\n', stderr);
  297. X    }
  298. X}
  299.  
  300.  
  301. X/*
  302. X *    Recursive routine that does the actual checking.
  303. X */
  304. Xvoid
  305. Xcheck(np)
  306. Xstruct name *        np;
  307. X{
  308. X    register struct depend *    dp;
  309. X    register struct line *        lp;
  310.  
  311.  
  312. X    if (np->n_flag & N_MARK)
  313. X        fatal("Circular dependency from %s", np->n_name);
  314.  
  315. X    np->n_flag |= N_MARK;
  316.  
  317. X    for (lp = np->n_line; lp; lp = lp->l_next)
  318. X        for (dp = lp->l_dep; dp; dp = dp->d_next)
  319. X            check(dp->d_name);
  320.  
  321. X    np->n_flag &= ~N_MARK;
  322. X}
  323.  
  324.  
  325. X/*
  326. X *    Look for circular dependancies.
  327. X *    ie.
  328. X *        a: b
  329. X *        b: a
  330. X *    is a circular dep
  331. X */
  332. Xvoid
  333. Xcirch()
  334. X{
  335. X    register struct name *    np;
  336.  
  337.  
  338. X    for (np = namehead.n_next; np; np = np->n_next)
  339. X        check(np);
  340. X}
  341.  
  342.  
  343. X/*
  344. X *    Check the target .PRECIOUS, and mark its dependentd as precious
  345. X */
  346. Xvoid
  347. Xprecious()
  348. X{
  349. X    register struct depend *    dp;
  350. X    register struct line *        lp;
  351. X    register struct name *        np;
  352.  
  353.  
  354. X    if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG))
  355. X        return;
  356.  
  357. X    for (lp = np->n_line; lp; lp = lp->l_next)
  358. X        for (dp = lp->l_dep; dp; dp = dp->d_next)
  359. X            dp->d_name->n_flag |= N_PREC;
  360. X}
  361. @//E*O*F check.c//
  362. chmod u=rw,g=rw,o=rw $OUT
  363.  
  364. echo x - input.c
  365. if test -f input.c ; then
  366.     echo input.c exists, putting output in $$input.c
  367.     OUT=$$input.c
  368.     STATUS=1
  369. else
  370.     OUT=input.c
  371. fi
  372. sed 's/^X//' > $OUT <<'@//E*O*F input.c//'
  373. X/*
  374. X *    Parse a makefile
  375. X */
  376.  
  377.  
  378. X#include <stdio.h>
  379. X#include    <ctype.h>
  380. X#include "h.h"
  381.  
  382.  
  383. Xstruct name        namehead;
  384. Xstruct name *        firstname;
  385.  
  386. Xchar             str1[LZ];        /*  General store  */
  387. Xchar            str2[LZ];
  388.  
  389.  
  390. X/*
  391. X *    Intern a name.  Return a pointer to the name struct
  392. X */
  393. Xstruct name *
  394. Xnewname(name)
  395. Xchar *            name;
  396. X{
  397. X    register struct name *    rp;
  398. X    register struct name *    rrp;
  399. X    register char *        cp;
  400.  
  401.  
  402. X    for
  403. X    (
  404. X        rp = namehead.n_next, rrp = &namehead;
  405. X        rp;
  406. X        rp = rp->n_next, rrp = rrp->n_next
  407. X    )
  408. X        if (strcmp(name, rp->n_name) == 0)
  409. X            return rp;
  410.  
  411. X    if ((rp = (struct name *)malloc(sizeof (struct name)))
  412. X                == (struct name *)0)
  413. X        fatal("No memory for name");
  414. X    rrp->n_next = rp;
  415. X    rp->n_next = (struct name *)0;
  416. X    if ((cp = malloc(strlen(name)+1)) == (char *)0)
  417. X        fatal("No memory for name");
  418. X    strcpy(cp, name);
  419. X    rp->n_name = cp;
  420. X    rp->n_line = (struct line *)0;
  421. X    rp->n_time = (time_t)0;
  422. X    rp->n_flag = 0;
  423.  
  424. X    return rp;
  425. X}
  426.  
  427.  
  428. X/*
  429. X *    Add a dependant to the end of the supplied list of dependants.
  430. X *    Return the new head pointer for that list.
  431. X */
  432. Xstruct depend *
  433. Xnewdep(np, dp)
  434. Xstruct name *        np;
  435. Xstruct depend *        dp;
  436. X{
  437. X    register struct depend *    rp;
  438. X    register struct depend *    rrp;
  439.  
  440.  
  441. X    if ((rp = (struct depend *)malloc(sizeof (struct depend)))
  442. X                == (struct depend *)0)
  443. X        fatal("No memory for dependant");
  444. X    rp->d_next = (struct depend *)0;
  445. X    rp->d_name = np;
  446.  
  447. X    if (dp == (struct depend *)0)
  448. X        return rp;
  449.  
  450. X    for (rrp = dp; rrp->d_next; rrp = rrp->d_next)
  451. X        ;
  452.  
  453. X    rrp->d_next = rp;
  454.  
  455. X    return dp;
  456. X}
  457.  
  458.  
  459. X/*
  460. X *    Add a command to the end of the supplied list of commands.
  461. X *    Return the new head pointer for that list.
  462. X */
  463. Xstruct cmd *
  464. Xnewcmd(str, cp)
  465. Xchar *            str;
  466. Xstruct cmd *        cp;
  467. X{
  468. X    register struct cmd *    rp;
  469. X    register struct cmd *    rrp;
  470. X    register char *        rcp;
  471.  
  472.  
  473. X    if (rcp = rindex(str, '\n'))
  474. X        *rcp = '\0';        /*  Loose newline  */
  475.  
  476. X    while (isspace(*str))
  477. X        str++;
  478.  
  479. X    if (*str == '\0')        /*  If nothing left, the exit  */
  480. X        return;
  481.  
  482. X    if ((rp = (struct cmd *)malloc(sizeof (struct cmd)))
  483. X                == (struct cmd *)0)
  484. X        fatal("No memory for command");
  485. X    rp->c_next = (struct cmd *)0;
  486. X    if ((rcp = malloc(strlen(str)+1)) == (char *)0)
  487. X        fatal("No memory for command");
  488. X    strcpy(rcp, str);
  489. X    rp->c_cmd = rcp;
  490.  
  491. X    if (cp == (struct cmd *)0)
  492. X        return rp;
  493.  
  494. X    for (rrp = cp; rrp->c_next; rrp = rrp->c_next)
  495. X        ;
  496.  
  497. X    rrp->c_next = rp;
  498.  
  499. X    return cp;
  500. X}
  501.  
  502.  
  503. X/*
  504. X *    Add a new 'line' of stuff to a target.  This check to see
  505. X *    if commands already exist for the target.  If flag is set,
  506. X *    the line is a double colon target.
  507. X *
  508. X *    Kludges:
  509. X *    i)  If the new name begins with a '.', and there are no dependents,
  510. X *        then the target must cease to be a target.  This is for .SUFFIXES.
  511. X *    ii) If the new name begins with a '.', with no dependents and has
  512. X *        commands, then replace the current commands.  This is for
  513. X *        redefining commands for a default rule.
  514. X *    Neither of these free the space used by dependents or commands,
  515. X *    since they could be used by another target.
  516. X */
  517. Xvoid
  518. Xnewline(np, dp, cp, flag)
  519. Xstruct name *        np;
  520. Xstruct depend *        dp;
  521. Xstruct cmd *        cp;
  522. X{
  523. X    bool            hascmds = FALSE;  /*  Target has commands  */
  524. X    register struct line *    rp;
  525. X    register struct line *    rrp;
  526.  
  527.  
  528. X    /* Handle the .SUFFIXES case */
  529. X    if (np->n_name[0] == '.' && !dp && !cp)
  530. X    {
  531. X        for (rp = np->n_line; rp; rp = rrp)
  532. X        {
  533. X            rrp = rp->l_next;
  534. X            free(rp);
  535. X        }
  536. X        np->n_line = (struct line *)0;
  537. X        np->n_flag &= ~N_TARG;
  538. X        return;
  539. X    }
  540.  
  541. X    /* This loop must happen since rrp is used later. */
  542. X    for
  543. X    (
  544. X        rp = np->n_line, rrp = (struct line *)0;
  545. X        rp;
  546. X        rrp = rp, rp = rp->l_next
  547. X    )
  548. X        if (rp->l_cmd)
  549. X            hascmds = TRUE;
  550.  
  551. X    if (hascmds && cp && !(np->n_flag & N_DOUBLE))
  552. X        /* Handle the implicit rules redefinition case */
  553. X        if (np->n_name[0] == '.' && dp == (struct depend *)0)
  554. X        {
  555. X            np->n_line->l_cmd = cp;
  556. X            return;
  557. X        }
  558. X        else
  559. X            error("Commands defined twice for target %s", np->n_name);
  560. X    if (np->n_flag & N_TARG)
  561. X        if (!(np->n_flag & N_DOUBLE) != !flag)        /* like xor */
  562. X            error("Inconsistent rules for target %s", np->n_name);
  563.  
  564. X    if ((rp = (struct line *)malloc(sizeof (struct line)))
  565. X                == (struct line *)0)
  566. X        fatal("No memory for line");
  567. X    rp->l_next = (struct line *)0;
  568. X    rp->l_dep = dp;
  569. X    rp->l_cmd = cp;
  570.  
  571. X    if (rrp)
  572. X        rrp->l_next = rp;
  573. X    else
  574. X        np->n_line = rp;
  575.  
  576. X    np->n_flag |= N_TARG;
  577. X    if (flag)
  578. X        np->n_flag |= N_DOUBLE;
  579. X}
  580.  
  581.  
  582. X/*
  583. X *    Parse input from the makefile, and construct a tree structure
  584. X *    of it.
  585. X */
  586. Xvoid
  587. Xinput(fd)
  588. XFILE *            fd;
  589. X{
  590. X    char *            p;        /*  General  */
  591. X    char *            q;
  592. X    struct name *        np;
  593. X    struct depend *        dp;
  594. X    struct cmd *        cp;
  595. X    bool            dbl;
  596.  
  597.  
  598. X    if (getline(str1, fd))    /*  Read the first line  */
  599. X        return;
  600.  
  601. X    for(;;)
  602. X    {
  603. X#ifdef os9
  604. X        if (*str1 == ' ')    /*  Rules without targets  */
  605. X#else
  606. X        if (*str1 == '\t')    /*  Rules without targets  */
  607. X#endif
  608. X            error("Rules not allowed here");
  609.  
  610. X        p = str1;
  611.  
  612. X        while (isspace(*p))    /*  Find first target  */
  613. X            p++;
  614.  
  615. X        while (((q = index(p, '=')) != (char *)0) &&
  616. X            (p != q) && (q[-1] == '\\'))    /*  Find value */
  617. X        {
  618. X            register char *        a;
  619.  
  620. X            a = q - 1;    /*  Del \ chr; move rest back  */
  621. X            p = q;
  622. X            while(*a++ = *q++)
  623. X                ;
  624. X        }
  625.  
  626. X        if (q != (char *)0)
  627. X        {
  628. X            register char *        a;
  629.  
  630. X            *q++ = '\0';        /*  Separate name and val  */
  631. X            while (isspace(*q))
  632. X                q++;
  633. X            if (p = rindex(q, '\n'))
  634. X                *p = '\0';
  635.  
  636. X            p = str1;
  637. X            if ((a = gettok(&p)) == (char *)0)
  638. X                error("No macro name");
  639.  
  640. X            setmacro(a, q);
  641.  
  642. X            if (getline(str1, fd))
  643. X                return;
  644. X            continue;
  645. X        }
  646.  
  647. X        expand(str1);
  648. X        p = str1;
  649.  
  650. X        while (((q = index(p, ':')) != (char *)0) &&
  651. X            (p != q) && (q[-1] == '\\'))    /*  Find dependents  */
  652. X        {
  653. X            register char *        a;
  654.  
  655. X            a = q - 1;    /*  Del \ chr; move rest back  */
  656. X            p = q;
  657. X            while(*a++ = *q++)
  658. X                ;
  659. X        }
  660.  
  661. X        if (q == (char *)0)
  662. X            error("No targets provided");
  663.  
  664. X        *q++ = '\0';    /*  Separate targets and dependents  */
  665.  
  666. X        if (*q == ':')        /* Double colon */
  667. X        {
  668. X            dbl = 1;
  669. X            q++;
  670. X        }
  671. X        else
  672. X            dbl = 0;
  673.  
  674. X        for (dp = (struct depend *)0; ((p = gettok(&q)) != (char *)0);)
  675. X                    /*  get list of dep's */
  676. X        {
  677. X            np = newname(p);        /*  Intern name  */
  678. X            dp = newdep(np, dp);        /*  Add to dep list */
  679. X        }
  680.  
  681. X        *((q = str1) + strlen(str1) + 1) = '\0';
  682. X            /*  Need two nulls for gettok (Remember separation)  */
  683.  
  684. X        cp = (struct cmd *)0;
  685. X        if (getline(str2, fd) == FALSE)        /*  Get commands  */
  686. X        {
  687. X#ifdef os9
  688. X            while (*str2 == ' ')
  689. X#else
  690. X            while (*str2 == '\t')
  691. X#endif
  692. X            {
  693. X                cp = newcmd(&str2[0], cp);
  694. X                if (getline(str2, fd))
  695. X                    break;
  696. X            }
  697. X        }
  698.  
  699. X        while ((p = gettok(&q)) != (char *)0)    /* Get list of targ's */
  700. X        {
  701. X            np = newname(p);        /*  Intern name  */
  702. X            newline(np, dp, cp, dbl);
  703. X            if (!firstname && p[0] != '.')
  704. X                firstname = np;
  705. X        }
  706.  
  707. X        if (feof(fd))                /*  EOF?  */
  708. X            return;
  709.  
  710. X        strcpy(str1, str2);
  711. X    }
  712. X}
  713. @//E*O*F input.c//
  714. chmod u=rw,g=rw,o=rw $OUT
  715.  
  716. echo x - macro.c
  717. if test -f macro.c ; then
  718.     echo macro.c exists, putting output in $$macro.c
  719.     OUT=$$macro.c
  720.     STATUS=1
  721. else
  722.     OUT=macro.c
  723. fi
  724. sed 's/^X//' > $OUT <<'@//E*O*F macro.c//'
  725. X/*
  726. X *    Macro control for make
  727. X */
  728.  
  729.  
  730. X#include "h.h"
  731.  
  732.  
  733. Xstruct macro *        macrohead;
  734.  
  735.  
  736. Xstruct macro *
  737. Xgetmp(name)
  738. Xchar *            name;
  739. X{
  740. X    register struct macro *    rp;
  741.  
  742. X    for (rp = macrohead; rp; rp = rp->m_next)
  743. X        if (strcmp(name, rp->m_name) == 0)
  744. X            return rp;
  745. X    return (struct macro *)0;
  746. X}
  747.  
  748.  
  749. Xchar *
  750. Xgetmacro(name)
  751. Xchar *            name;
  752. X{
  753. X    struct macro *        mp;
  754.  
  755. X    if (mp = getmp(name))
  756. X        return mp->m_val;
  757. X    else
  758. X        return "";
  759. X}
  760.  
  761.  
  762. Xstruct macro *
  763. Xsetmacro(name, val)
  764. Xchar *            name;
  765. Xchar *            val;
  766. X{
  767. X    register struct macro *    rp;
  768. X    register char *        cp;
  769.  
  770.  
  771. X            /*  Replace macro definition if it exists  */
  772. X    for (rp = macrohead; rp; rp = rp->m_next)
  773. X        if (strcmp(name, rp->m_name) == 0)
  774. X        {
  775. X            free(rp->m_val);    /*  Free space from old  */
  776. X            break;
  777. X        }
  778.  
  779. X    if (!rp)        /*  If not defined, allocate space for new  */
  780. X    {
  781. X        if ((rp = (struct macro *)malloc(sizeof (struct macro)))
  782. X                     == (struct macro *)0)
  783. X            fatal("No memory for macro");
  784.  
  785. X        rp->m_next = macrohead;
  786. X        macrohead = rp;
  787. X        rp->m_flag = FALSE;
  788.  
  789. X        if ((cp = malloc(strlen(name)+1)) == (char *)0)
  790. X            fatal("No memory for macro");
  791. X        strcpy(cp, name);
  792. X        rp->m_name = cp;
  793. X    }
  794.  
  795. X    if ((cp = malloc(strlen(val)+1)) == (char *)0)
  796. X        fatal("No memory for macro");
  797. X    strcpy(cp, val);        /*  Copy in new value  */
  798. X    rp->m_val = cp;
  799.  
  800. X    return rp;
  801. X}
  802.  
  803.  
  804. X/*
  805. X *    Do the dirty work for expand
  806. X */
  807. Xvoid
  808. Xdoexp(to, from, len, buf)
  809. Xchar **            to;
  810. Xchar *            from;
  811. Xint *            len;
  812. Xchar *            buf;
  813. X{
  814. X    register char *        rp;
  815. X    register char *        p;
  816. X    register char *        q;
  817. X    register struct macro *    mp;
  818.  
  819.  
  820. X    rp = from;
  821. X    p = *to;
  822. X    while (*rp)
  823. X    {
  824. X        if (*rp != '$')
  825. X        {
  826. X            *p++ = *rp++;
  827. X            (*len)--;
  828. X        }
  829. X        else
  830. X        {
  831. X            q = buf;
  832. X            if (*++rp == '{')
  833. X                while (*++rp && *rp != '}')
  834. X                    *q++ = *rp;
  835. X            else if (*rp == '(')
  836. X                while (*++rp && *rp != ')')
  837. X                    *q++ = *rp;
  838. X            else if (!*rp)
  839. X            {
  840. X                *p++ = '$';
  841. X                break;
  842. X            }
  843. X            else
  844. X                *q++ = *rp;
  845. X            *q = '\0';
  846. X            if (*rp)
  847. X                rp++;
  848. X            if (!(mp = getmp(buf)))
  849. X                mp = setmacro(buf, "");
  850. X            if (mp->m_flag)
  851. X                fatal("Infinitely recursive macro %s", mp->m_name);
  852. X            mp->m_flag = TRUE;
  853. X            *to = p;
  854. X            doexp(to, mp->m_val, len, buf);
  855. X            p = *to;
  856. X            mp->m_flag = FALSE;
  857. X        }
  858. X        if (*len <= 0)
  859. X            error("Expanded line too line");
  860. X    }
  861. X    *p = '\0';
  862. X    *to = p;
  863. X}
  864.  
  865.  
  866. X/*
  867. X *    Expand any macros in str.
  868. X */
  869. Xvoid
  870. Xexpand(str)
  871. Xchar *        str;
  872. X{
  873. X    static char        a[LZ];
  874. X    static char        b[LZ];
  875. X    char *            p = str;
  876. X    int            len = LZ-1;
  877.  
  878. X    strcpy(a, str);
  879. X    doexp(&p, a, &len, b);
  880. X}
  881. @//E*O*F macro.c//
  882. chmod u=rw,g=rw,o=rw $OUT
  883.  
  884. echo x - main.c
  885. if test -f main.c ; then
  886.     echo main.c exists, putting output in $$main.c
  887.     OUT=$$main.c
  888.     STATUS=1
  889. else
  890.     OUT=main.c
  891. fi
  892. sed 's/^X//' > $OUT <<'@//E*O*F main.c//'
  893. X/*
  894. X *    make [-f makefile] [-ins] [target(s) ...]
  895. X *
  896. X *    (Better than EON mk but not quite as good as UNIX make)
  897. X *
  898. X *    -f makefile name
  899. X *    -i ignore exit status
  900. X *    -n Pretend to make
  901. X *    -p Print all macros & targets
  902. X *    -q Question up-to-dateness of target.  Return exit status 1 if not
  903. X *    -r Don't not use inbuilt rules
  904. X *    -s Make silently
  905. X *    -t Touch files instead of making them
  906. X *    -m Change memory requirements (EON only)
  907. X */
  908.  
  909. X#include <stdio.h>
  910. X#include "h.h"
  911.  
  912. X#ifdef unix
  913. X#include <sys/errno.h>
  914. X#endif
  915. X#ifdef eon
  916. X#include <sys/err.h>
  917. X#endif
  918. X#ifdef os9
  919. X#include <errno.h>
  920. X#endif
  921.  
  922.  
  923. X#ifdef eon
  924. X#define MEMSPACE    (16384)
  925. X#endif
  926.  
  927.  
  928. Xchar *            myname;
  929. Xchar *            makefile;    /*  The make file  */
  930. X#ifdef eon
  931. Xunsigned        memspace = MEMSPACE;
  932. X#endif
  933.  
  934. XFILE *            ifd;        /*  Input file desciptor  */
  935. Xbool            domake = TRUE;    /*  Go through the motions option  */
  936. Xbool            ignore = FALSE;    /*  Ignore exit status option  */
  937. Xbool            silent = FALSE;    /*  Silent option  */
  938. Xbool            print = FALSE;    /*  Print debuging information  */
  939. Xbool            rules = TRUE;    /*  Use inbuilt rules  */
  940. Xbool            dotouch = FALSE;/*  Touch files instead of making  */
  941. Xbool            quest = FALSE;    /*  Question up-to-dateness of file  */
  942.  
  943.  
  944. Xvoid
  945. Xmain(argc, argv)
  946. Xint            argc;
  947. Xchar **            argv;
  948. X{
  949. X    register char *        p;        /*  For argument processing  */
  950. X    int            estat = 0;    /*  For question  */
  951. X    register struct name *    np;
  952.  
  953.  
  954. X    myname = (argc-- < 1) ? "make" : *argv++;
  955.  
  956. X    while ((argc > 0) && (**argv == '-'))
  957. X    {
  958. X        argc--;        /*  One less to process  */
  959. X        p = *argv++;    /*  Now processing this one  */
  960.  
  961. X        while (*++p != '\0')
  962. X        {
  963. X            switch(*p)
  964. X            {
  965. X            case 'f':    /*  Alternate file name  */
  966. X                if (*++p == '\0')
  967. X                {
  968. X                    if (argc-- <= 0)
  969. X                        usage();
  970. X                    p = *argv++;
  971. X                }
  972. X                makefile = p;
  973. X                goto end_of_args;
  974. X#ifdef eon
  975. X            case 'm':    /*  Change space requirements  */
  976. X                if (*++p == '\0')
  977. X                {
  978. X                    if (argc-- <= 0)
  979. X                        usage();
  980. X                    p = *argv++;
  981. X                }
  982. X                memspace = atoi(p);
  983. X                goto end_of_args;
  984. X#endif
  985. X            case 'n':    /*  Pretend mode  */
  986. X                domake = FALSE;
  987. X                break;
  988. X            case 'i':    /*  Ignore fault mode  */
  989. X                ignore = TRUE;
  990. X                break;
  991. X            case 's':    /*  Silent about commands  */
  992. X                silent = TRUE;
  993. X                break;
  994. X            case 'p':
  995. X                print = TRUE;
  996. X                break;
  997. X            case 'r':
  998. X                rules = FALSE;
  999. X                break;
  1000. X            case 't':
  1001. X                dotouch = TRUE;
  1002. X                break;
  1003. X            case 'q':
  1004. X                quest = TRUE;
  1005. X                break;
  1006. X            default:    /*  Wrong option  */
  1007. X                usage();
  1008. X            }
  1009. X        }
  1010. X    end_of_args:;
  1011. X    }
  1012.  
  1013. X#ifdef eon
  1014. X    if (initalloc(memspace) == 0xffff)  /*  Must get memory for alloc  */
  1015. X        fatal("Cannot initalloc memory");
  1016. X#endif
  1017.  
  1018. X    if (strcmp(makefile, "-") == 0)    /*  Can use stdin as makefile  */
  1019. X        ifd = stdin;
  1020. X    else
  1021. X        if (!makefile)        /*  If no file, then use default */
  1022. X        {
  1023. X            if ((ifd = fopen(DEFN1, "r")) == (FILE *)0)
  1024. X#ifdef eon
  1025. X                if (errno != ER_NOTF)
  1026. X                    fatal("Can't open %s; error %02x", DEFN1, errno);
  1027. X#endif
  1028. X#ifdef unix
  1029. X                if (errno != ENOENT)
  1030. X                    fatal("Can't open %s; error %02x", DEFN1, errno);
  1031. X#endif
  1032. X#ifndef os9
  1033. X            if ((ifd == (FILE *)0)
  1034. X                  && ((ifd = fopen(DEFN2, "r")) == (FILE *)0))
  1035. X                fatal("Can't open %s", DEFN2);
  1036. X#else
  1037. X                fatal("Can't open %s", DEFN1);
  1038. X#endif
  1039. X        }
  1040. X        else
  1041. X            if ((ifd = fopen(makefile, "r")) == (FILE *)0)
  1042. X                fatal("Can't open %s", makefile);
  1043.  
  1044. X    makerules();
  1045.  
  1046. X    setmacro("$", "$");
  1047.  
  1048. X    while (argc && (p = index(*argv, '=')))
  1049. X    {
  1050. X        char        c;
  1051.  
  1052. X        c = *p;
  1053. X        *p = '\0';
  1054. X        setmacro(*argv, p+1);
  1055. X        *p = c;
  1056.  
  1057. X        argv++;
  1058. X        argc--;
  1059. X    }
  1060.  
  1061. X    input(ifd);    /*  Input all the gunga  */
  1062. X    fclose(ifd);    /*  Finished with makefile  */
  1063. X    lineno = 0;    /*  Any calls to error now print no line number */
  1064.  
  1065. X    if (print)
  1066. X        prt();    /*  Print out structures  */
  1067.  
  1068. X    np = newname(".SILENT");
  1069. X    if (np->n_flag & N_TARG)
  1070. X        silent = TRUE;
  1071.  
  1072. X    np = newname(".IGNORE");
  1073. X    if (np->n_flag & N_TARG)
  1074. X        ignore = TRUE;
  1075.  
  1076. X    precious();
  1077.  
  1078. X    if (!firstname)
  1079. X        fatal("No targets defined");
  1080.  
  1081. X    circh();    /*  Check circles in target definitions  */
  1082.  
  1083. X    if (!argc)
  1084. X        estat = make(firstname, 0);
  1085. X    else while (argc--)
  1086. X    {
  1087. X        if (!print && !silent && strcmp(*argv, "love") == 0)
  1088. X            printf("Not war!\n");
  1089. X        estat |= make(newname(*argv++), 0);
  1090. X    }
  1091.  
  1092. X    if (quest)
  1093. X        exit(estat);
  1094. X    else
  1095. X        exit(0);
  1096. X}
  1097.  
  1098.  
  1099. Xusage()
  1100. X{
  1101. X    fprintf(stderr, "Usage: %s [-f makefile] [-inpqrst] [macro=val ...] [target(s) ...]\n", myname);
  1102. X    exit(1);
  1103. X}
  1104.  
  1105.  
  1106. Xvoid
  1107. Xfatal(msg, a1, a2, a3, a4, a5, a6)
  1108. Xchar    *msg;
  1109. X{
  1110. X    fprintf(stderr, "%s: ", myname);
  1111. X    fprintf(stderr, msg, a1, a2, a3, a4, a5, a6);
  1112. X    fputc('\n', stderr);
  1113. X    exit(1);
  1114. X}
  1115. @//E*O*F main.c//
  1116. chmod u=rw,g=rw,o=rw $OUT
  1117.  
  1118. echo x - make.c
  1119. if test -f make.c ; then
  1120.     echo make.c exists, putting output in $$make.c
  1121.     OUT=$$make.c
  1122.     STATUS=1
  1123. else
  1124.     OUT=make.c
  1125. fi
  1126. sed 's/^X//' > $OUT <<'@//E*O*F make.c//'
  1127. X/*
  1128. X *    Do the actual making for make
  1129. X */
  1130.  
  1131. X#include <stdio.h>
  1132. X#ifdef unix
  1133. X#include <sys/types.h>
  1134. X#include <sys/stat.h>
  1135. X#include <sys/errno.h>
  1136. X#endif
  1137. X#ifdef eon
  1138. X#include <sys/stat.h>
  1139. X#include <sys/err.h>
  1140. X#endif
  1141. X#ifdef os9
  1142. X#include <time.h>
  1143. X#include <os9.h>
  1144. X#include <modes.h>
  1145. X#include <direct.h>
  1146. X#include <errno.h>
  1147. X#endif
  1148. X#include "h.h"
  1149.  
  1150.  
  1151.  
  1152. X/*
  1153. X *    Exec a shell that returns exit status correctly (/bin/esh).
  1154. X *    The standard EON shell returns the process number of the last
  1155. X *    async command, used by the debugger (ugg).
  1156. X *    [exec on eon is like a fork+exec on unix]
  1157. X */
  1158. Xint
  1159. Xdosh(string, shell)
  1160. Xchar *            string;
  1161. Xchar *            shell;
  1162. X{
  1163. X    int    number;
  1164.  
  1165. X#ifdef unix
  1166. X    return system(string);
  1167. X#endif
  1168. X#ifdef eon
  1169. X    return ((number = execl(shell, shell,"-c", string, 0)) == -1) ?
  1170. X        -1:    /* couldn't start the shell */
  1171. X        wait(number);    /* return its exit status */
  1172. X#endif
  1173. X#ifdef os9
  1174. X    int    status, pid;
  1175.  
  1176. X    strcat(string, "\n");
  1177. X    if ((number = os9fork(shell, strlen(string), string, 0, 0, 0)) == -1)
  1178. X        return -1;        /* Couldn't start a shell */
  1179. X    do
  1180. X    {
  1181. X        if ((pid = wait(&status)) == -1)
  1182. X            return -1;    /* child already died!?!? */
  1183. X    } while (pid != number);
  1184.  
  1185. X    return status;
  1186. X#endif
  1187. X}
  1188.  
  1189.  
  1190. X/*
  1191. X *    Do commands to make a target
  1192. X */
  1193. Xvoid
  1194. Xdocmds1(np, lp)
  1195. Xstruct name *        np;
  1196. Xstruct line *        lp;
  1197. X{
  1198. X    bool            ssilent;
  1199. X    bool            signore;
  1200. X    int            estat;
  1201. X    register char *        q;
  1202. X    register char *        p;
  1203. X    char *            shell;
  1204. X    register struct cmd *    cp;
  1205.  
  1206.  
  1207. X    if (*(shell = getmacro("SHELL")) == '\0')
  1208. X#ifdef eon
  1209. X        shell = ":bin/esh";
  1210. X#endif
  1211. X#ifdef unix
  1212. X        shell = "/bin/sh";
  1213. X#endif
  1214. X#ifdef os9
  1215. X        shell = "shell";
  1216. X#endif
  1217.  
  1218. X    for (cp = lp->l_cmd; cp; cp = cp->c_next)
  1219. X    {
  1220. X        strcpy(str1, cp->c_cmd);
  1221. X        expand(str1);
  1222. X        q = str1;
  1223. X        ssilent = silent;
  1224. X        signore = ignore;
  1225. X        while ((*q == '@') || (*q == '-'))
  1226. X        {
  1227. X            if (*q == '@')       /*  Specific silent  */
  1228. X                ssilent = TRUE;
  1229. X            else           /*  Specific ignore  */
  1230. X                signore = TRUE;
  1231. X            q++;           /*  Not part of the command  */
  1232. X        }
  1233.  
  1234. X        if (!domake)
  1235. X            ssilent = 0;
  1236.  
  1237. X        if (!ssilent)
  1238. X            fputs("    ", stdout);
  1239.  
  1240. X        for (p=q; *p; p++)
  1241. X        {
  1242. X            if (*p == '\n' && p[1] != '\0')
  1243. X            {
  1244. X                *p = ' ';
  1245. X                if (!ssilent)
  1246. X                    fputs("\\\n", stdout);
  1247. X            }
  1248. X            else if (!ssilent)
  1249. X                putchar(*p);
  1250. X        }
  1251. X        if (!ssilent)
  1252. X            putchar('\n');
  1253.  
  1254. X        if (domake)
  1255. X        {            /*  Get the shell to execute it  */
  1256. X            if ((estat = dosh(q, shell)) != 0)
  1257. X            {
  1258. X                if (estat == -1)
  1259. X                    fatal("Couldn't execute %s", shell);
  1260. X                else
  1261. X                {
  1262. X                    printf("%s: Error code %d", myname, estat);
  1263. X                    if (signore)
  1264. X                        fputs(" (Ignored)\n", stdout);
  1265. X                    else
  1266. X                    {
  1267. X                        putchar('\n');
  1268. X                        if (!(np->n_flag & N_PREC))
  1269. X                            if (unlink(np->n_name) == 0)
  1270. X                                printf("%s: '%s' removed.\n", myname, np->n_name);
  1271. X                        exit(estat);
  1272. X                    }
  1273. X                }
  1274. X            }
  1275. X        }
  1276. X    }
  1277. X}
  1278.  
  1279.  
  1280. Xdocmds(np)
  1281. Xstruct name *        np;
  1282. X{
  1283. X    register struct line *    lp;
  1284.  
  1285.  
  1286. X    for (lp = np->n_line; lp; lp = lp->l_next)
  1287. X        docmds1(np, lp);
  1288. X}
  1289.  
  1290.  
  1291. X#ifdef os9
  1292. X/*
  1293. X *    Some stuffing around to get the modified time of a file
  1294. X *    in an os9 file system
  1295. X */
  1296. Xgetmdate(fd, tbp)
  1297. Xstruct sgtbuf *        tbp;
  1298. X{
  1299. X    struct registers    regs;
  1300. X    static struct fildes    fdbuf;
  1301.  
  1302.  
  1303. X    regs.rg_a = fd;
  1304. X    regs.rg_b = SS_FD;
  1305. X    regs.rg_x = &fdbuf;
  1306. X    regs.rg_y = sizeof (fdbuf);
  1307.  
  1308. X    if (_os9(I_GETSTT, ®s) == -1)
  1309. X    {
  1310. X        errno = regs.rg_b & 0xff;
  1311. X        return -1;
  1312. X    }
  1313. X    if (tbp)
  1314. X    {
  1315. X        _strass(tbp, fdbuf.fd_date, sizeof (fdbuf.fd_date));
  1316. X        tbp->t_second = 0;    /* Files are only acurate to mins */
  1317. X    }
  1318. X    return 0;
  1319. X}
  1320.  
  1321.  
  1322. X/*
  1323. X *    Kludge routine to return an aproximation of how many
  1324. X *    seconds since 1980.  Dates will be in order, but will not
  1325. X *    be lineer
  1326. X */
  1327. Xtime_t
  1328. Xcnvtime(tbp)
  1329. Xstruct sgtbuf        *tbp;
  1330. X{
  1331. X    long            acc;
  1332.  
  1333.  
  1334. X    acc = tbp->t_year - 80;        /* Baseyear is 1980 */
  1335. X    acc = acc * 12 + tbp->t_month;
  1336. X    acc = acc * 31 + tbp->t_day;
  1337. X    acc = acc * 24 + tbp->t_hour;
  1338. X    acc = acc * 60 + tbp->t_minute;
  1339. X    acc = acc * 60 + tbp->t_second;
  1340.  
  1341. X    return acc;
  1342. X}
  1343.  
  1344.  
  1345. X/*
  1346. X *    Get the current time in the internal format
  1347. X */
  1348. Xtime(tp)
  1349. Xtime_t *        tp;
  1350. X{
  1351. X    struct sgtbuf        tbuf;
  1352.  
  1353.  
  1354. X    if (getime(&tbuf) < 0)
  1355. X        return -1;
  1356.  
  1357. X    if (tp)
  1358. X        *tp = cnvtime(&tbuf);
  1359.  
  1360. X    return 0;
  1361. X}
  1362. X#endif
  1363.  
  1364.  
  1365. X/*
  1366. X *    Get the modification time of a file.  If the first
  1367. X *    doesn't exist, it's modtime is set to 0.
  1368. X */
  1369. Xvoid
  1370. Xmodtime(np)
  1371. Xstruct name *        np;
  1372. X{
  1373. X#ifdef unix
  1374. X    struct stat        info;
  1375. X    int            fd;
  1376.  
  1377.  
  1378. X    if (stat(np->n_name, &info) < 0)
  1379. X    {
  1380. X        if (errno != ENOENT)
  1381. X            fatal("Can't open %s; error %d", np->n_name, errno);
  1382.  
  1383. X        np->n_time = 0L;
  1384. X    }
  1385. X    else
  1386. X        np->n_time = info.st_mtime;
  1387. X#endif
  1388. X#ifdef eon
  1389. X    struct stat        info;
  1390. X    int            fd;
  1391.  
  1392.  
  1393. X    if ((fd = open(np->n_name, 0)) < 0)
  1394. X    {
  1395. X        if (errno != ER_NOTF)
  1396. X            fatal("Can't open %s; error %02x", np->n_name, errno);
  1397.  
  1398. X        np->n_time = 0L;
  1399. X    }
  1400. X    else if (getstat(fd, &info) < 0)
  1401. X        fatal("Can't getstat %s; error %02x", np->n_name, errno);
  1402. X    else
  1403. X        np->n_time = info.st_mod;
  1404.  
  1405. X    close(fd);
  1406. X#endif
  1407. X#ifdef os9
  1408. X    struct sgtbuf        info;
  1409. X    int            fd;
  1410.  
  1411.  
  1412. X    if ((fd = open(np->n_name, 0)) < 0)
  1413. X    {
  1414. X        if (errno != E_PNNF)
  1415. X            fatal("Can't open %s; error %02x", np->n_name, errno);
  1416.  
  1417. X        np->n_time = 0L;
  1418. X    }
  1419. X    else if (getmdate(fd, &info) < 0)
  1420. X        fatal("Can't getstat %s; error %02x", np->n_name, errno);
  1421. X    else
  1422. X        np->n_time = cnvtime(&info);
  1423.  
  1424. X    close(fd);
  1425. X#endif
  1426. X}
  1427.  
  1428.  
  1429. X/*
  1430. X *    Update the mod time of a file to now.
  1431. X */
  1432. Xvoid
  1433. Xtouch(np)
  1434. Xstruct name *        np;
  1435. X{
  1436. X    char            c;
  1437. X    int            fd;
  1438.  
  1439.  
  1440. X    if (!domake || !silent)
  1441. X        printf("    touch(%s)\n", np->n_name);
  1442.  
  1443. X    if (domake)
  1444. X    {
  1445. X#ifdef unix
  1446. X        long        a[2];
  1447.  
  1448. X        a[0] = a[1] = time(0);
  1449. X        if (utime(np->n_name, &a[0]) < 0)
  1450. X            printf("%s: '%s' not touched - non-existant\n",
  1451. X                    myname, np->n_name);
  1452. X#endif
  1453. X#ifdef eon
  1454. X        if ((fd = open(np->n_name, 0)) < 0)
  1455. X            printf("%s: '%s' not touched - non-existant\n",
  1456. X                    myname, np->n_name);
  1457. X        else
  1458. X        {
  1459. X            uread(fd, &c, 1, 0);
  1460. X            uwrite(fd, &c, 1);
  1461. X        }
  1462. X        close(fd);
  1463. X#endif
  1464. X#ifdef os9
  1465. X        /*
  1466. X         *    Strange that something almost as totally useless
  1467. X         *    as this is easy to do in os9!
  1468. X         */
  1469. X        if ((fd = open(np->n_name, S_IWRITE)) < 0)
  1470. X            printf("%s: '%s' not touched - non-existant\n",
  1471. X                    myname, np->n_name);
  1472. X        close(fd);
  1473. X#endif
  1474. X    }
  1475. X}
  1476.  
  1477.  
  1478. X/*
  1479. X *    Recursive routine to make a target.
  1480. X */
  1481. Xint
  1482. Xmake(np, level)
  1483. Xstruct name *        np;
  1484. Xint            level;
  1485. X{
  1486. X    register struct depend *    dp;
  1487. X    register struct line *        lp;
  1488. X    register struct depend *    qdp;
  1489. X    time_t                dtime = 1;
  1490. X    bool                didsomething = 0;
  1491.  
  1492.  
  1493. X    if (np->n_flag & N_DONE)
  1494. X        return 0;
  1495.  
  1496. X    if (!np->n_time)
  1497. X        modtime(np);        /*  Gets modtime of this file  */
  1498.  
  1499. X    if (rules)
  1500. X    {
  1501. X        for (lp = np->n_line; lp; lp = lp->l_next)
  1502. X            if (lp->l_cmd)
  1503. X                break;
  1504. X        if (!lp)
  1505. X            dyndep(np);
  1506. X    }
  1507.  
  1508. X    if (!(np->n_flag & N_TARG) && np->n_time == 0L)
  1509. X        fatal("Don't know how to make %s", np->n_name);
  1510.  
  1511. X    for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next)
  1512. X    {
  1513. X        for (dp = lp->l_dep; dp; dp = dp->d_next)
  1514. X        {
  1515. X            make(dp->d_name, level+1);
  1516. X            if (np->n_time < dp->d_name->n_time)
  1517. X                qdp = newdep(dp->d_name, qdp);
  1518. X            dtime = max(dtime, dp->d_name->n_time);
  1519. X        }
  1520. X        if (!quest && (np->n_flag & N_DOUBLE) && (np->n_time < dtime))
  1521. X        {
  1522. X            make1(np, lp, qdp);    /* free()'s qdp */
  1523. X            dtime = 1;
  1524. X            qdp = (struct depend *)0;
  1525. X            didsomething++;
  1526. X        }
  1527. X    }
  1528.  
  1529. X    np->n_flag |= N_DONE;
  1530.  
  1531. X    if (quest)
  1532. X    {
  1533. X        long        t;
  1534.  
  1535. X        t = np->n_time;
  1536. X        time(&np->n_time);
  1537. X        return t < dtime;
  1538. X    }
  1539. X    else if (np->n_time < dtime && !(np->n_flag & N_DOUBLE))
  1540. X    {
  1541. X        make1(np, (struct line *)0, qdp);    /* free()'s qdp */
  1542. X        time(&np->n_time);
  1543. X    }
  1544. X    else if (level == 0 && !didsomething)
  1545. X        printf("%s: '%s' is up to date\n", myname, np->n_name);
  1546. X    return 0;
  1547. X}
  1548.  
  1549.  
  1550. Xmake1(np, lp, qdp)
  1551. Xregister struct depend *    qdp;
  1552. Xstruct line *            lp;
  1553. Xstruct name *            np;
  1554. X{
  1555. X    register struct depend *    dp;
  1556.  
  1557.  
  1558. X    if (dotouch)
  1559. X        touch(np);
  1560. X    else
  1561. X    {
  1562. X        strcpy(str1, "");
  1563. X        for (dp = qdp; dp; dp = qdp)
  1564. X        {
  1565. X            if (strlen(str1))
  1566. X                strcat(str1, " ");
  1567. X            strcat(str1, dp->d_name->n_name);
  1568. X            qdp = dp->d_next;
  1569. X            free(dp);
  1570. X        }
  1571. X        setmacro("?", str1);
  1572. X        setmacro("@", np->n_name);
  1573. X        if (lp)        /* lp set if doing a :: rule */
  1574. X            docmds1(np, lp);
  1575. X        else
  1576. X            docmds(np);
  1577. X    }
  1578. X}
  1579. @//E*O*F make.c//
  1580. chmod u=rw,g=rw,o=rw $OUT
  1581.  
  1582. echo x - reader.c
  1583. if test -f reader.c ; then
  1584.     echo reader.c exists, putting output in $$reader.c
  1585.     OUT=$$reader.c
  1586.     STATUS=1
  1587. else
  1588.     OUT=reader.c
  1589. fi
  1590. sed 's/^X//' > $OUT <<'@//E*O*F reader.c//'
  1591. X/*
  1592. X *    Read in makefile
  1593. X */
  1594.  
  1595.  
  1596. X#include <stdio.h>
  1597. X#include    <ctype.h>
  1598. X#include "h.h"
  1599.  
  1600.  
  1601. Xint            lineno;
  1602.  
  1603.  
  1604. X/*
  1605. X *    Syntax error handler.  Print message, with line number, and exits.
  1606. X */
  1607. Xvoid
  1608. Xerror(msg, a1, a2, a3)
  1609. Xchar *            msg;
  1610. X{
  1611. X    fprintf(stderr, "%s: ", myname);
  1612. X    fprintf(stderr, msg, a1, a2, a3);
  1613. X    if (lineno)
  1614. X        fprintf(stderr, " near line %d", lineno);
  1615. X    fputc('\n', stderr);
  1616. X    exit(1);
  1617. X}
  1618.  
  1619.  
  1620. X/*
  1621. X *    Read a line into the supplied string of length LZ.  Remove
  1622. X *    comments, ignore blank lines. Deal with    quoted (\) #, and
  1623. X *    quoted newlines.  If EOF return TRUE.
  1624. X */
  1625. Xbool
  1626. Xgetline(str, fd)
  1627. Xchar *        str;
  1628. XFILE *        fd;
  1629. X{
  1630. X    register char *        p;
  1631. X    char *            q;
  1632. X    int            pos = 0;
  1633.  
  1634.  
  1635. X    for (;;)
  1636. X    {
  1637. X        if (fgets(str+pos, LZ-pos, fd) == (char *)0)
  1638. X            return TRUE;        /*  EOF  */
  1639.  
  1640. X        lineno++;
  1641.  
  1642. X        if ((p = index(str+pos, '\n')) == (char *)0)
  1643. X            error("Line too long");
  1644.  
  1645. X        if (p[-1] == '\\')
  1646. X        {
  1647. X            p[-1] = '\n';
  1648. X            pos = p - str;
  1649. X            continue;
  1650. X        }
  1651.  
  1652. X        p = str;
  1653. X        while (((q = index(p, '#')) != (char *)0) &&
  1654. X            (p != q) && (q[-1] == '\\'))
  1655. X        {
  1656. X            char    *a;
  1657.  
  1658. X            a = q - 1;    /*  Del \ chr; move rest back  */
  1659. X            p = q;
  1660. X            while (*a++ = *q++)
  1661. X                ;
  1662. X        }
  1663. X        if (q != (char *)0)
  1664. X        {
  1665. X            q[0] = '\n';
  1666. X            q[1] = '\0';
  1667. X        }
  1668.  
  1669. X        p = str;
  1670. X        while (isspace(*p))    /*  Checking for blank  */
  1671. X            p++;
  1672.  
  1673. X        if (*p != '\0')
  1674. X            return FALSE;
  1675. X        pos = 0;
  1676. X    }
  1677. X}
  1678.  
  1679.  
  1680. X/*
  1681. X *    Get a word from the current line, surounded by white space.
  1682. X *    return a pointer to it. String returned has no white spaces
  1683. X *    in it.
  1684. X */
  1685. Xchar *
  1686. Xgettok(ptr)
  1687. Xchar    **ptr;
  1688. X{
  1689. X    register char *        p;
  1690.  
  1691.  
  1692. X    while (isspace(**ptr))    /*  Skip spaces  */
  1693. X        (*ptr)++;
  1694.  
  1695. X    if (**ptr == '\0')    /*  Nothing after spaces  */
  1696. X        return NULL;
  1697.  
  1698. X    p = *ptr;        /*  word starts here  */
  1699.  
  1700. X    while ((**ptr != '\0') && (!isspace(**ptr)))
  1701. X        (*ptr)++;    /*  Find end of word  */
  1702.  
  1703. X    *(*ptr)++ = '\0';    /*  Terminate it  */
  1704.  
  1705. X    return(p);
  1706. X}
  1707. @//E*O*F reader.c//
  1708. chmod u=rw,g=rw,o=rw $OUT
  1709.  
  1710. echo x - rules.c
  1711. if test -f rules.c ; then
  1712.     echo rules.c exists, putting output in $$rules.c
  1713.     OUT=$$rules.c
  1714.     STATUS=1
  1715. else
  1716.     OUT=rules.c
  1717. fi
  1718. sed 's/^X//' > $OUT <<'@//E*O*F rules.c//'
  1719. X/*
  1720. X *    Control of the implicit suffix rules
  1721. X */
  1722.  
  1723.  
  1724. X#include "h.h"
  1725.  
  1726.  
  1727. X/*
  1728. X *    Return a pointer to the suffix of a name
  1729. X */
  1730. Xchar *
  1731. Xsuffix(name)
  1732. Xchar *            name;
  1733. X{
  1734. X    return rindex(name, '.');
  1735. X}
  1736.  
  1737.  
  1738. X/*
  1739. X *    Dynamic dependency.  This routine applies the suffis rules
  1740. X *    to try and find a source and a set of rules for a missing
  1741. X *    target.  If found, np is made into a target with the implicit
  1742. X *    source name, and rules.  Returns TRUE if np was made into
  1743. X *    a target.
  1744. X */
  1745. Xbool
  1746. Xdyndep(np)
  1747. Xstruct name *        np;
  1748. X{
  1749. X    register char *        p;
  1750. X    register char *        q;
  1751. X    register char *        suff;        /*  Old suffix  */
  1752. X    register char *        basename;    /*  Name without suffix  */
  1753. X    struct name *        op;        /*  New dependent  */
  1754. X    struct name *        sp;        /*  Suffix  */
  1755. X    struct line *        lp;
  1756. X    struct depend *        dp;
  1757. X    char *            newsuff;
  1758.  
  1759.  
  1760. X    p = str1;
  1761. X    q = np->n_name;
  1762. X    if (!(suff = suffix(q)))
  1763. X        return FALSE;        /* No suffix */
  1764. X    while (q < suff)
  1765. X        *p++ = *q++;
  1766. X    *p = '\0';
  1767. X    basename = setmacro("*", str1)->m_val;
  1768.  
  1769. X    if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG))
  1770. X        return FALSE;
  1771.  
  1772. X    for (lp = sp->n_line; lp; lp = lp->l_next)
  1773. X        for (dp = lp->l_dep; dp; dp = dp->d_next)
  1774. X        {
  1775. X            newsuff = dp->d_name->n_name;
  1776. X            if (strlen(suff)+strlen(newsuff)+1 >= LZ)
  1777. X                fatal("Suffix rule too long");
  1778. X            p = str1;
  1779. X            q = newsuff;
  1780. X            while (*p++ = *q++)
  1781. X                ;
  1782. X            p--;
  1783. X            q = suff;
  1784. X            while (*p++ = *q++)
  1785. X                ;
  1786. X            sp = newname(str1);
  1787. X            if (sp->n_flag & N_TARG)
  1788. X            {
  1789. X                p = str1;
  1790. X                q = basename;
  1791. X                if (strlen(basename) + strlen(newsuff)+1 >= LZ)
  1792. X                    fatal("Implicit name too long");
  1793. X                while (*p++ = *q++)
  1794. X                    ;
  1795. X                p--;
  1796. X                q = newsuff;
  1797. X                while (*p++ = *q++)
  1798. X                    ;
  1799. X                op = newname(str1);
  1800. X                if (!op->n_time)
  1801. X                    modtime(op);
  1802. X                if (op->n_time)
  1803. X                {
  1804. X                    dp = newdep(op, 0);
  1805. X                    newline(np, dp, sp->n_line->l_cmd, 0);
  1806. X                    setmacro("<", op->n_name);
  1807. X                    return TRUE;
  1808. X                }
  1809. X            }
  1810. X        }
  1811. X    return FALSE;
  1812. X}
  1813.  
  1814.  
  1815. X/*
  1816. X *    Make the default rules
  1817. X */
  1818. Xvoid
  1819. Xmakerules()
  1820. X{
  1821. X    struct cmd *        cp;
  1822. X    struct name *        np;
  1823. X    struct depend *        dp;
  1824.  
  1825.  
  1826. X#ifdef eon
  1827. X    setmacro("BDSCC", "asm");
  1828. X    /*    setmacro("BDSCFLAGS", "");    */
  1829. X    cp = newcmd("$(BDSCC) $(BDSCFLAGS) -n $<", 0);
  1830. X    np = newname(".c.o");
  1831. X    newline(np, 0, cp, 0);
  1832.  
  1833. X    setmacro("CC", "c");
  1834. X    setmacro("CFLAGS", "-O");
  1835. X    cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
  1836. X    np = newname(".c.obj");
  1837. X    newline(np, 0, cp, 0);
  1838.  
  1839. X    setmacro("M80", "asm -n");
  1840. X    /*    setmacro("M80FLAGS", "");    */
  1841. X    cp = newcmd("$(M80) $(M80FLAGS) $<", 0);
  1842. X    np = newname(".mac.o");
  1843. X    newline(np, 0, cp, 0);
  1844.  
  1845. X    setmacro("AS", "zas");
  1846. X    /*    setmacro("ASFLAGS", "");    */
  1847. X    cp = newcmd("$(ZAS) $(ASFLAGS) -o $@ $<", 0);
  1848. X    np = newname(".as.obj");
  1849. X    newline(np, 0, cp, 0);
  1850.  
  1851. X    np = newname(".as");
  1852. X    dp = newdep(np, 0);
  1853. X    np = newname(".obj");
  1854. X    dp = newdep(np, dp);
  1855. X    np = newname(".c");
  1856. X    dp = newdep(np, dp);
  1857. X    np = newname(".o");
  1858. X    dp = newdep(np, dp);
  1859. X    np = newname(".mac");
  1860. X    dp = newdep(np, dp);
  1861. X    np = newname(".SUFFIXES");
  1862. X    newline(np, dp, 0, 0);
  1863. X#endif
  1864.  
  1865. X/*
  1866. X *    Some of the UNIX implicit rules
  1867. X */
  1868. X#ifdef unix
  1869. X    setmacro("CC", "cc");
  1870. X    setmacro("CFLAGS", "-O");
  1871. X    cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
  1872. X    np = newname(".c.o");
  1873. X    newline(np, 0, cp, 0);
  1874.  
  1875. X    setmacro("AS", "as");
  1876. X    cp = newcmd("$(AS) -o $@ $<", 0);
  1877. X    np = newname(".s.o");
  1878. X    newline(np, 0, cp, 0);
  1879.  
  1880. X    setmacro("YACC", "yacc");
  1881. X    /*    setmacro("YFLAGS", "");    */
  1882. X    cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
  1883. X    cp = newcmd("mv y.tab.c $@", cp);
  1884. X    np = newname(".y.c");
  1885. X    newline(np, 0, cp, 0);
  1886.  
  1887. X    cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
  1888. X    cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
  1889. X    cp = newcmd("rm y.tab.c", cp);
  1890. X    cp = newcmd("mv y.tab.o $@", cp);
  1891. X    np = newname(".y.o");
  1892. X    newline(np, 0, cp, 0);
  1893.  
  1894. X    np = newname(".s");
  1895. X    dp = newdep(np, 0);
  1896. X    np = newname(".o");
  1897. X    dp = newdep(np, dp);
  1898. X    np = newname(".c");
  1899. X    dp = newdep(np, dp);
  1900. X    np = newname(".y");
  1901. X    dp = newdep(np, dp);
  1902. X    np = newname(".SUFFIXES");
  1903. X    newline(np, dp, 0, 0);
  1904. X#endif
  1905. X#ifdef os9
  1906. X/*
  1907. X *    Fairlight use an enhanced version of the C sub-system.
  1908. X *    They have a specialised macro pre-processor.
  1909. X */
  1910. X    setmacro("CC", "cc");
  1911. X    setmacro("CFLAGS", "-z");
  1912. X    cp = newcmd("$(CC) $(CFLAGS) -r $<", 0);
  1913.  
  1914. X    np = newname(".c.r");
  1915. X    newline(np, 0, cp, 0);
  1916. X    np = newname(".ca.r");
  1917. X    newline(np, 0, cp, 0);
  1918. X    np = newname(".a.r");
  1919. X    newline(np, 0, cp, 0);
  1920. X    np = newname(".o.r");
  1921. X    newline(np, 0, cp, 0);
  1922. X    np = newname(".mc.r");
  1923. X    newline(np, 0, cp, 0);
  1924. X    np = newname(".mca.r");
  1925. X    newline(np, 0, cp, 0);
  1926. X    np = newname(".ma.r");
  1927. X    newline(np, 0, cp, 0);
  1928. X    np = newname(".mo.r");
  1929. X    newline(np, 0, cp, 0);
  1930.  
  1931. X    np = newname(".r");
  1932. X    dp = newdep(np, 0);
  1933. X    np = newname(".mc");
  1934. X    dp = newdep(np, dp);
  1935. X    np = newname(".mca");
  1936. X    dp = newdep(np, dp);
  1937. X    np = newname(".c");
  1938. X    dp = newdep(np, dp);
  1939. X    np = newname(".ca");
  1940. X    dp = newdep(np, dp);
  1941. X    np = newname(".ma");
  1942. X    dp = newdep(np, dp);
  1943. X    np = newname(".mo");
  1944. X    dp = newdep(np, dp);
  1945. X    np = newname(".o");
  1946. X    dp = newdep(np, dp);
  1947. X    np = newname(".a");
  1948. X    dp = newdep(np, dp);
  1949. X    np = newname(".SUFFIXES");
  1950. X    newline(np, dp, 0, 0);
  1951. X#endif
  1952. X}
  1953. @//E*O*F rules.c//
  1954. chmod u=rw,g=rw,o=rw $OUT
  1955.  
  1956. echo Inspecting for damage in transit...
  1957. temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
  1958. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  1959. cat > $temp <<\!!!
  1960.       38     313    1803 README
  1961.       11      22     134 Makefile
  1962.      130     414    2457 h.h
  1963.      115     316    2100 check.c
  1964.      340    1124    6577 input.c
  1965.      156     396    2366 macro.c
  1966.      222     683    4336 main.c
  1967.      452    1202    7682 make.c
  1968.      116     318    1795 reader.c
  1969.      234     740    4819 rules.c
  1970.     1814    5528   34069 total
  1971. !!!
  1972. wc  README Makefile h.h check.c input.c macro.c main.c make.c reader.c rules.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  1973. if test -s $dtemp ; then
  1974.     echo "Ouch [diff of wc output]:"
  1975.     cat $dtemp
  1976.     STATUS=1
  1977. elif test $STATUS = 0 ; then
  1978.     echo "No problems found."
  1979. else
  1980.     echo "WARNING -- PROBLEMS WERE FOUND..."
  1981. fi
  1982. exit $STATUS
  1983.